/// <summary>
// CodeFx - A .NET framework
// Laurent Morisseau
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// Laurent Morisseau
/// </summary>
/// <author><a href="mailto:laurent.morisseau@gmail.com">Laurent Morisseau</a></author>

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Text;
namespace CodeFx.Web
{
        public class Persistance<T> where T:new()
        {
            #region Constructor             
            public Persistance()
            {
                this.attribute = PersistanceAttribute.GetData(this.GetType());
                this.scenario = (ConfigurationManager.GetSection("ConfigSection") as ConfigSection).ScenariiPersistanceCollection[this.attribute.Scenarii.ToString()];
            }
            #endregion

            public static Persistance<T> Current = new Persistance<T>();


            #region Private Properties
            private PersistanceAttribute.Data attribute;
            private ScenarioPersistanceElement scenario;
            #endregion

            #region Public Properties
            public PersistanceAttribute.Data Attribute
            {
                get { return this.attribute; }
            }
            #endregion

            #region Methods Id
            
            protected virtual string IdNull
            {
                get
                {
                    if (typeof(T).Equals(typeof(Int16)) || typeof(T).Equals(typeof(Int32)))
                        return "0";
                    else
                        return string.Empty;
                }
            }

            public virtual bool IdIsNull
            {
                get
                {
                    switch (this.attribute.Mode)
                    {
                        case EPersistanceMode.Session:
                            return (HttpContext.Current.Session == null) || (HttpContext.Current.Session[this.Attribute.Key] == null);
                        case EPersistanceMode.Cache:
                            string id = this.Id;
                            if (!string.IsNullOrEmpty(id))
                                return String.Equals(id,this.IdNull);
                            else
                                return true;
                        case EPersistanceMode.Items:
                            return (HttpContext.Current.Items == null) || (HttpContext.Current.Items[this.Attribute.Key] == null);
                        default:
                            return true;
                    }
                }
            }

            public virtual bool IdIsNotNull
            {
                get
                {
                    return !this.IdIsNull;
                }
            }

            public bool EqualsId(object obj)
            {
                if (this.Id != null)
                    return String.Equals(this.Id,obj.ToString());
                else
                    return false;
            }

            public virtual string Id
            {
                get
                {
                    if ((HttpContext.Current.Session != null) && (HttpContext.Current.Session[this.Attribute.Key] != null))
                        return HttpContext.Current.Session[this.Attribute.Key].ToString();
                    else
                        return (string)null;
                }
                set
                {
                    if (!string.IsNullOrEmpty(value))
                        HttpContext.Current.Session[this.attribute.Key] = value;
                    else if (this.IdIsNotNull)
                        HttpContext.Current.Session.Remove(this.Attribute.Key);
                }
            }

            private void SetId(T ObjectValue)
            {
                this.Id = GetKey(ObjectValue);
            }

            public virtual string GetKey(T ObjectValue)
            {
                if (ObjectValue != null)
                    return ObjectValue.ToString();
                else
                    return string.Empty ;
            } 

            #endregion

            #region Methods Object

            protected virtual T ObjectNull
            {
                get{
                return default(T);}
            }

            public virtual bool ObjectIsNull
            {
                get
                {
                    switch (this.attribute.Mode)
                    {
                        case EPersistanceMode.Cache:
                        case EPersistanceMode.Session:
                        case EPersistanceMode.Items:
                            return EqualsObject(this.ObjectNull);
                        default:
                            return true;
                    }
                }
            }

            public virtual bool ObjectIsNotNull
            {
                get
                {
                    return !this.ObjectIsNull;
                }
            }


            public bool EqualsObject(T objectToTest)
            {
                T Object = this.Object;
                if (Object != null)
                    return Object.Equals(objectToTest);
                else
                    return false;
            }

            public virtual void SetObject( T ObjectToPersist)
            {

                if ((ObjectToPersist == null) || (String.IsNullOrEmpty(GetKey(ObjectToPersist))))
                {
                    this.RemoveObject();
                    return;
                }    
                SetObject(ObjectToPersist, GetKey(ObjectToPersist));
            }

            public virtual void SetObject(T ObjectToPersist, string Key)
            {
                if (ObjectToPersist == null)
                {
                    this.RemoveObject(Key);
                    return;
                }
                switch (this.attribute.Mode)
                {
                    case EPersistanceMode.Items:
                        HttpContext.Current.Items[this.Attribute.Key] = ObjectToPersist;
                        break;
                    case EPersistanceMode.Session:
                        if (HttpContext.Current.Session != null)
                        {
                            HttpContext.Current.Session.Remove(this.Attribute.Key);
                            HttpContext.Current.Session.Add(this.Attribute.Key, ObjectToPersist);
                        }
                        break;
                    case EPersistanceMode.Cache:
                        this.Id = Key;
                        string Key_Cache = this.Key_Cache(Key);
                        HttpContext.Current.Cache.Remove(Key_Cache);
                        HttpContext.Current.Cache.Add(Key_Cache, ObjectToPersist, null,
                                    scenario.PersistanceAbsoluteExpiration,
                                    scenario.PersistanceSlidingExpiration,
                                    scenario.PersistancePriority, null);  
                        break;
                }
            }

            public virtual T Select
            {
                get
                {
                    return default(T);
                }
            }

            public virtual T GetSelect(string Key)
            {
                return default(T);
            }

            public virtual T Object
            {
                get{
                if (this.IdIsNotNull)
                    return this.GetObject(this.Id);
                else
                    return this.GetObject(string.Empty);}
            }

            public virtual T ObjectOrDefault
            {
                get
                {
                    T t = this.Object;
                    if (t != null)
                        return t;
                    else
                    {
                        t = new T();
                        /// Mise en persistance de la nouvelle instance
                        SetObject(t);
                        return t;
                    }
                }
            }

            public virtual T GetObject(string Key)
            {
                
                string key_Cache = this.Key_Cache(Key);
                switch (this.attribute.Mode)
                {
                    case EPersistanceMode.Items:
                        if (HttpContext.Current.Items[this.attribute.Key] != null)
                            return (T)HttpContext.Current.Items[this.attribute.Key];
                        else
                            return default(T);
                    case EPersistanceMode.Session:
                        if ((HttpContext.Current.Session != null) && (HttpContext.Current.Session[this.attribute.Key] != null))
                            return (T)HttpContext.Current.Session[this.attribute.Key];
                        else
                        {
                            T newT = new T();
                            if (string.IsNullOrEmpty(Key))
                                newT = this.Select;
                            else if (!string.IsNullOrEmpty(Key))
                                newT = this.GetSelect(Key);
                            if (newT != null)
                                this.SetObject(newT);
                            return newT;
                        }
                    case EPersistanceMode.Cache:
                        if (HttpContext.Current.Cache[key_Cache] != null)
                        {
                            this.Id = Key;
                            return (T)HttpContext.Current.Cache[key_Cache];
                        }
                        else
                        {
                            T newT = new T();
                            if (string.IsNullOrEmpty(Key) && this.IdIsNull)
                                newT = this.Select;
                            else if (!string.IsNullOrEmpty(Key))
                                newT = this.GetSelect(Key);
                            else if (this.IdIsNotNull)
                                newT = this.GetSelect(this.Id);
                            if (newT != null)
                            {
                                this.Id = Key;
                                this.SetObject(newT);
                            }
                            return newT;
                        }
                    default:
                        return default(T);

	            }
            }
             
            public virtual void RemoveObject()
            {
                if (this.IdIsNull)
                   this.RemoveObject(string.Empty);
               else
                   this.RemoveObject(this.Id);
            }

            public virtual void RemoveObject(string key)
            {
                if (key != null)
                {
                    HttpContext context = HttpContext.Current;
                    if (context.Cache != null)
                        context.Cache.Remove(this.Key_Cache(key));
                    if (context.Session != null)
                        context.Session.Remove(this.attribute.Key);
                }
            }

            #endregion

            #region protected method
            protected string Key_Cache(string Key)
            {
                StringBuilder _sb = new StringBuilder( this.Attribute.Key );
                if (!string.IsNullOrEmpty(Key))
                {
                    _sb.Append( "_" );
                    _sb.Append( Key);
                }
                switch (this.Attribute.Level)
                {
                    case EPersistanceLevel.Private:
                    _sb.Append( "_" );
                    _sb.Append(MyGuid.Current);
                     break;
                }
                return _sb.ToString();
             }
    
            #endregion
        }
}
